`include "common_define.vh"

module epu_state_machine(
    input clk,
    input rst_n,

    input [2:0] cdc_counter,
    input [23:0] shift_reg,
    input [10:0] len_counter,

    input [10:0] payload_len,
    inout more_datagram,
    input circulating_frame,

    output reg state_change,
    output reg [3:0] state

);
    reg [3:0] next_state;

    always@(posedge clk or negedge rst_n)begin
        if(!rst_n) begin
            state <= `IDLE;
        end else begin
            state <= next_state;
        end
    end

    always@(*)begin
        next_state=state;
        state_change = 1'b0;
        case(state)
            `IDLE:begin
                if(shift_reg[15:8]==8'h55 && cdc_counter==7) begin
                    next_state = `PREAMBLE;
                    state_change = 1'b1;
                end
            end
            `PREAMBLE:begin
                if(cdc_counter==7) begin
                    if(shift_reg[15:8]==8'h5d) begin
                        next_state = `ETHERNET_HEADER;
                        state_change = 1'b1;
                    end
                     else if(shift_reg[15:8]!=8'h55) begin
                        next_state = `IDLE;
                        state_change = 1'b1;
                    end
                end
            end
            `ETHERNET_HEADER:begin
                if(cdc_counter==7 && len_counter==14)begin
                    if({shift_reg[7:0],shift_reg[15:8]}==16'h88A4) begin
                        next_state = `ETHERCAT_HEADER;
                        state_change = 1'b1;
                    end 
                    else if({shift_reg[7:0],shift_reg[15:8]}==16'h8800) begin
                        next_state = `IP_UDP;
                        state_change = 1'b1;
                    end 
                    else if({shift_reg[7:0],shift_reg[15:8]}==16'h8100) begin
                        next_state = `VLAN;
                        state_change = 1'b1;
                    end 
                    else begin
                        next_state = `ERROR;
                        state_change = 1'b1;
                    end
                end
            end
            `VLAN:begin
                if(cdc_counter==7 && len_counter==4)begin
                    if({shift_reg[7:0],shift_reg[15:8]}==16'h88A4) begin
                        next_state = `ETHERCAT_HEADER;
                        state_change = 1'b1;
                    end 
                    else if({shift_reg[7:0],shift_reg[15:8]}==16'h8800) begin
                        next_state = `IP_UDP;
                        state_change = 1'b1;
                    end 
                    else begin
                        next_state = `ERROR;
                        state_change = 1'b1;
                    end
                end
            end
            `IP_UDP:begin
                if(cdc_counter==7 && len_counter==24) begin
                    if({shift_reg[7:0],shift_reg[15:8]}!=16'h88A4) begin
                        next_state = `ERROR;
                        state_change = 1'b1;
                    end 
                end
                else if(cdc_counter==7 && len_counter==28) begin
                    next_state = `ETHERCAT_HEADER;
                    state_change = 1'b1;
                end
            end
            `ETHERCAT_HEADER:begin
                if(cdc_counter==7 && len_counter==2) begin
                    if(shift_reg[15:12]==4'b0001) begin
                        next_state = `DATAGRAM_HEADER;
                        state_change = 1'b1;
                    end 
                    else begin
                        next_state = `ERROR;
                        state_change = 1'b1;
                    end
                end
            end
            `DATAGRAM_HEADER:begin
                if(cdc_counter==7 && len_counter==10) begin
                    next_state = `DATAGRAM_PAYLOAD;
                    state_change = 1'b1;
                end
            end
            `DATAGRAM_PAYLOAD:begin
                if(circulating_frame==1) begin
                    next_state = `ERROR;
                    state_change = 1'b1;
                end
                if(cdc_counter==7 && len_counter==payload_len) begin
                    next_state = `WKC;
                    state_change = 1'b1;
                end
            end
            `WKC:begin
                if(cdc_counter==7 && len_counter==2) begin
                    if(more_datagram==1'b1) begin
                        next_state = `DATAGRAM_HEADER;
                        state_change = 1'b1;
                    end
                    else begin
                        next_state = `FCS;
                        state_change = 1'b1;
                    end
                end
            end
            `FCS:begin
                if(cdc_counter==7 && len_counter==4) begin
                    next_state = `IDLE;
                    state_change = 1'b1;
                end
            end
        endcase
    end

endmodule